﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using AppCompress.Model;
using System.Windows.Forms;
using ICSharpCode.SharpZipLib.Zip;
using System.Text.RegularExpressions;

namespace AppCompress.Utils
{
    public class FileUtils
    {
        private readonly List<Model.File> FileList = new List<Model.File>(); //选择打开的文件

        private readonly string rootPath = @"C:\Users\lbt\Desktop\临时文件夹"; //临时文件夹地址

        /// <summary>
        /// 根据目录，将子目录及文件装在特定的file类中
        /// </summary>
        /// <param name="dir"></param>
        /// <returns></returns>
        public List<Model.File> GetAllFileInfo(DirectoryInfo dir)
        {
            FileList.Clear();
            Model.File file = new Model.File();
            file.Name = dir.Name;
            file.Path = dir.FullName;
            file.IsDirectory = 1;
            FileList.Add(file);
            //递归，生成最终file对象
            GetFileInfo(dir, file);

            return FileList;
        }

        /// <summary>
        /// 递归获取每个文件和文件夹
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="parentFile"></param>
        public void GetFileInfo(DirectoryInfo dir, Model.File parentFile)
        {
            parentFile.FileInfos = new List<Model.File>();
            FileInfo[] allFile = dir.GetFiles();
            DirectoryInfo[] allDir = dir.GetDirectories();
            if (allFile.Length <= 0 && allDir.Length <= 0)
            {
                return;
            }
            // 分别对这个路径下的文件和文件夹 进行遍历
            if (allDir.Length > 0)
            {
                foreach (DirectoryInfo d in allDir)
                {
                    Model.File file = new Model.File();
                    file.Name = d.Name;
                    file.Path = d.FullName;
                    file.IsDirectory = 1;
                    //与父级目录关联
                    file.ParentFile = parentFile;
                    parentFile.FileInfos.Add(file);
                    GetFileInfo(d, file);
                }
            }
            if (allFile.Length > 0)
            {
                Model.File file;
                foreach (FileInfo d in allFile)
                {
                    file = new Model.File(d.Name, d.FullName, 0, parentFile);
                    parentFile.FileInfos.Add(file);
                }
            }
        }

        //设置子节点状态
        public void setchild(TreeNode node, ref bool check)
        {
            foreach (TreeNode child in node.Nodes)
            {
                child.Checked = node.Checked;
            }
            check = true;
        }

        //设置父节点状态
        public void setparent(TreeNode node)
        {
            if (node.Parent != null)
            {
                //如果当前节点状态为勾选，则需要所有兄弟节点都勾选才能勾选父节点
                if (node.Checked)
                    foreach (TreeNode brother in node.Parent.Nodes)
                    {
                        if (!brother.Checked)
                            return;
                    }
                node.Parent.Checked = node.Checked;
            }
        }

        /// <summary>
        /// 获取选中的文件，从根节点开始遍历
        /// </summary>
        /// <param name="root">根节点</param>
        /// <returns></returns>
        public List<TreeNode> GetSelectedFile(TreeNode root)
        {
            List<TreeNode> list = new List<TreeNode>();
            GetSelectedAllFile(root, list);
            return list;
        }

        /// <summary>
        /// 从根节点开始递归，获取到被选中的节点
        /// </summary>
        /// <param name="root">根节点</param>
        /// <param name="list">已经被选中的节点列表</param>
        public void GetSelectedAllFile(TreeNode root, List<TreeNode> list)
        {
            foreach (TreeNode child in root.Nodes)
            {
                if (child.Checked)
                {
                    list.Add(child);
                }
                if (child.Nodes != null && child.Nodes.Count > 0)
                {
                    GetSelectedAllFile(child, list);
                }
            }
        }

        /// <summary>
        /// 将选中的文件及文件夹一一拷贝一份放到指定目录中
        /// </summary>
        /// <param name="nodes">被选中的节点</param>
        /// <param name="rootNode">根节点</param>
        /// <returns>临时文件地址</returns>
        public string CopyAndCreate(List<TreeNode> nodes, TreeNode rootNode)
        {
            createDirectory(rootPath);
            //遍历rootnode
            List<Model.File> allFiles = GetAllFileInfo(new DirectoryInfo(rootNode.Name));
            string pre = rootNode.Name; //前缀  D:\file\text
            List<string> parentPath;
            for (int i = 0; i < nodes.Count; i++)
            {
                TreeNode node = nodes[i];
                if (Directory.Exists(node.Name)) //判断是否是目录
                {
                    parentPath = getParentFile(allFiles, node.Name);
                    if (parentPath.Count > 0)
                    {
                        for (int j = 0; j < parentPath.Count; j++)
                        {
                            string path = parentPath[j].Replace(pre, "");
                            if (!Directory.Exists(rootPath + path))
                            {
                                createDirectory(rootPath + path); //C:\Users\lbt\Desktop\临时文件夹\文件夹名字
                            }
                            //在指定路径上建一个目录
                        }
                        createDirectory(rootPath + parentPath[0].Replace(pre, "") + @"\" + node.Text); //C:\Users\lbt\Desktop\临时文件夹\文件夹名字
                    }
                    else
                    {
                        createDirectory(rootPath + @"\" + node.Text); //C:\Users\lbt\Desktop\临时文件夹\文件夹名字
                    }
                }
                else
                {
                    //若是文件，需要先看看上级文件夹是否创建
                    parentPath = getParentFile(allFiles, node.Name); //获取文件夹名字（除去前缀）
                    for (int j = 0; j < parentPath.Count; j++)
                    {
                        string resultPath = rootPath;
                        if (parentPath[0].Contains(pre))
                        {
                            resultPath += parentPath[0].Replace(pre, "");
                            if (!Directory.Exists(resultPath))
                            {
                                createDirectory(resultPath);
                            }
                            CopyFile(node.Name, resultPath + @"\" + node.Text);
                            break;
                        }
                    }
                    if (parentPath.Count <= 0)
                    {
                        CopyFile(node.Name, rootPath + @"\" + node.Text);
                    }
                }
            }
            return rootPath;
        }

        /// <summary>
        /// 获取所有父级目录，一般第一个为直亲父目录
        /// </summary>
        /// <param name="allFiles">整个树</param>
        /// <param name="path">需要寻找文件的路径</param>
        /// <returns>父级目录地址列表</returns>
        public List<string> getParentFile(List<Model.File> allFiles, string path)
        {
            List<string> parentPaths = new List<string>();
            for (int i = 0; i < allFiles.Count; i++)
            {
                Model.File file = allFiles[i];
                if (file.Name == path)
                {
                    getParentFileList(file, parentPaths);
                }
                else
                {
                    checkFilePath(file, path, parentPaths);
                }
            }
            return parentPaths;
        }

        /// <summary>
        /// 递归将文件的上级目录添加至 集合中
        /// </summary>
        /// <param name="file"></param>
        /// <param name="parentPaths">父级目录地址列表</param>
        public void getParentFileList(Model.File file, List<string> parentPaths)
        {
            //除了一级目录以外的其他目录
            if (file.ParentFile != null && file.ParentFile.ParentFile != null)
            {
                parentPaths.Add(file.ParentFile.Path);
                getParentFileList(file.ParentFile, parentPaths);
            }
        }

        /// <summary>
        /// 找他的子级里 是否存在path
        /// </summary>
        /// <param name="file"></param>
        /// <param name="path">需要查找的地址</param>
        /// <param name="parentPaths">父级目录地址列表</param>
        public void checkFilePath(Model.File file, string path, List<string> parentPaths)
        {
            if (file.FileInfos != null)
            {
                for (int j = 0; j < file.FileInfos.Count; j++)
                {
                    if (file.FileInfos[j].Path == path)
                    {
                        getParentFileList(file.FileInfos[j], parentPaths);
                        return;
                    }
                    checkFilePath(file.FileInfos[j], path, parentPaths);
                }
            }
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="rootPath">创建文件夹的地址</param>
        public void createDirectory(string rootPath)
        {
            try
            {
                Directory.CreateDirectory(rootPath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        /// <summary>
        /// 拷贝文件
        /// </summary>
        /// <param name="sourceFile">源文件地址</param>
        /// <param name="path">目标文件地址</param>
        public void CopyFile(string sourceFile, string path)
        {
            try
            {
                if (!Directory.Exists(path))
                {
                    System.IO.File.Copy(sourceFile, path);
                }
                else
                {
                    Console.WriteLine("不存在文件夹");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        public bool checkoutPath(string path)
        {
            Regex regex = new Regex(@"^([a-zA-Z]:\\)?[^\/\:\*\?\""\<\>\|\,]*$");
            Match m = regex.Match(path);
            if (!m.Success)
            {
                MessageBox.Show("非法的文件保存路径，请重新选择或输入！");
                return false;
            }
            return true;
        }
    }
}